package view.displayManagers;

import java.awt.Color;
import java.awt.Point;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JButton;

import model.Board;
import model.pieces.Bishop;
import model.pieces.King;
import model.pieces.Knight;
import model.pieces.Pawn;
import model.pieces.Queen;
import model.pieces.Rook;

/**
 * Class enables updating the game board display and refreshing the display after changes   
 */
public abstract class GameDisplayTool {

	/**
	 * Holds information needed for clicked chess button
	 */
	public static class ClickedPiece {
		
		// members
		private Point position; // piece's position on board
		private List<Point> moves; // piece's move list
		
		// public methods
		
		public ClickedPiece(Point position) {
			
			// set members according to given values
			this.position = position;
			// initialize move list
			moves = new LinkedList<Point>();
		}

		public Point getPosition() { return position; }
		public void setPosition(int newRow, int newCol) { position.move(newRow, newCol); }
		public List<Point> getMoveList() { return moves; }
	}
	
	// members
	private Map<String, ImageIcon> iconMap; // holds icons for board buttons
	private Color light; // light board button color
	private Color dark; // dark board button color
	private int boardSize; // game board' size
	private List<JButton> boardButtons; // board buttons
	private Board gameBoard; // reference to game board
	
	/**
	 * Updates icon of given button, according to the piece at button's position on board
	 * @param gameBoard- reference to game board
	 * @param row- row index of current button
	 * @param col- column index of current button
	 * @param buttonToUpdate- button to update its icon
	 * @param iconMap- map of available icons
	 */
	private void updateButtonIcon(Board gameBoard, int row, int col, JButton buttonToUpdate) {
			
			// so far it is not known if a piece is at this position
			buttonToUpdate.setIcon(null);
			
			// check which piece (if any) is at this position
			if (gameBoard.getPiece(row, col) instanceof Pawn) { // check if a Pawn is placed
				
				// update image according to indicated player
				if (gameBoard.getPiece(row, col).getPlayer()) {
					// piece assigned to first player
					buttonToUpdate.setIcon(iconMap.get("white_Pawn"));
					
				} else {
					// piece assigned to second player
					buttonToUpdate.setIcon(iconMap.get("black_Pawn"));
				}
				
			} else if (gameBoard.getPiece(row, col) instanceof Knight) { // check if a Knight is placed
				
				if (gameBoard.getPiece(row, col).getPlayer()) {
					// piece assigned to first player
					buttonToUpdate.setIcon(iconMap.get("white_Knight"));
					
				} else {
					// piece assigned to second player
					buttonToUpdate.setIcon(iconMap.get("black_Knight"));
				}
				
			} else if (gameBoard.getPiece(row, col) instanceof Rook) { // check if a Rook is placed
				
				if (gameBoard.getPiece(row, col).getPlayer()) {
					// piece assigned to first player
					buttonToUpdate.setIcon(iconMap.get("white_Rook"));
					
				} else {
					// piece assigned to second player
					buttonToUpdate.setIcon(iconMap.get("black_Rook"));
				}
				
			} else if (gameBoard.getPiece(row, col) instanceof Bishop) { // check if a Bishop is placed
				
				if (gameBoard.getPiece(row, col).getPlayer()) {
					// piece assigned to first player
					buttonToUpdate.setIcon(iconMap.get("white_Bishop"));
					
				} else {
					// piece assigned to second player
					buttonToUpdate.setIcon(iconMap.get("black_Bishop"));
				}
				
			} else if (gameBoard.getPiece(row, col) instanceof King) { // check if a King is placed
				
				if (gameBoard.getPiece(row, col).getPlayer()) {
					// piece assigned to first player
					buttonToUpdate.setIcon(iconMap.get("white_King"));
					
				} else {
					// piece assigned to second player
					buttonToUpdate.setIcon(iconMap.get("black_King"));
				}
				
			} else if (gameBoard.getPiece(row, col) instanceof Queen) { // check if a Queen is placed
				
				if (gameBoard.getPiece(row, col).getPlayer()) {
					// piece assigned to first player
					buttonToUpdate.setIcon(iconMap.get("white_Queen"));
					
				} else {
					// piece assigned to second player
					buttonToUpdate.setIcon(iconMap.get("black_Queen"));
				}
			}
		}

	/**
	 * Constructor- creates a new display tool for human controlled game
	 * @param iconMap- button icons
	 * @param light- light button color
	 * @param dark- dark button color
	 * @param boardSize- game board size
	 */
	public GameDisplayTool(Map<String, ImageIcon> iconMap, Color light, Color dark, int boardSize, List<JButton> boardButtons, Board gameBoard) {
		
		// set members according to given values
		this.iconMap = iconMap;
		this.light = light;
		this.dark = dark;
		this.boardSize = boardSize;		
		this.boardButtons = boardButtons;
		this.gameBoard = gameBoard;
	}
	
	/**
	 * Returns the light board button color
	 * @return light color of board button
	 */
	public Color getLightColor() { return light; }
	
	/**
	 * Returns the dark board button color
	 * @return dark color of board button
	 */
	public Color getDarkColor() { return dark; }

	/**
	 * Returns game board's size
	 * @return game board's size
	 */
	public int getBoardSize() { return boardSize; }
	
	/**
	 * Returns the board buttons
	 * @return the board buttons
	 */
	public List<JButton> getBoardButtons() { return boardButtons; } 
	
	/**
	 * Returns the board buttons icons
	 * @return board buttons icons
	 */
	public Map<String, ImageIcon> getIconMap() { return iconMap; }
	
	/**
	 * Sets each button's color to default (according to its position).
	 * Uses game board to update locations of pieces, and updates buttons' icons accordingly
	 */
	public void displayBoard() {
		
		// total number of buttons of board 
		int buttonNumber = boardSize * boardSize;
		
		// scan all board buttons
		for (int i = 0 ; i < buttonNumber ; ++i) {
			
			// get current button from button list
			JButton currBtn = boardButtons.get(i);
									
			// calculate board entry matching current index
			int row = (i / boardSize) + 1;
			int col = (i % boardSize) + 1;
			
			// set color back to default according to button's position
			if ((i/boardSize) % 2 == 0) {
				currBtn.setBackground(dark);
				
				if (i % 2 == 0) {
					currBtn.setBackground(light);					
				} 
			} else {
				currBtn.setBackground(dark);
				
				if (i % 2 != 0) {
					currBtn.setBackground(light);					
				}
			}
			
			// update current button's icon
			updateButtonIcon(gameBoard, row, col, currBtn);
		}
	}
	
	/**
	 * Refreshes board display by updating icon and color of buttons that were changed
	 * @param lastToBeClicked- details of the button that was the last to be clicked
	 */
	public void refreshBoardDisplay(ClickedPiece lastToBeClicked) {
			
			// update display of last-to-be-clicked button and its reachable positions
			List<Point> moveList = lastToBeClicked.getMoveList();
			
			// if exists, add saved position
			if (lastToBeClicked.getPosition() != null) {			
				moveList.add(lastToBeClicked.getPosition());
			}
		
			// scan all marked buttons
			for (Point currPosition : moveList) {
				
				// get button matching current position on board
				int index = (currPosition.x-1)*boardSize + currPosition.y-1; // convert row-column index to linear index
				JButton currBtn = boardButtons.get(index); 
	
				// set color back to default according to button's position
				if ((index/boardSize) % 2 == 0) {
					currBtn.setBackground(dark);
					
					if (index % 2 == 0) {
						currBtn.setBackground(light);					
					} 
				} else {
					currBtn.setBackground(dark);
					
					if (index % 2 != 0) {
						currBtn.setBackground(light);					
					}
				}
				
				// update current button's icon
				updateButtonIcon(gameBoard, currPosition.x, currPosition.y, currBtn);
			}
		}	
}